print("****************面向对象****************")
print("****************封装****************")
-- 面向对象 类 都是基于表table来实现
-- 元表相关的知识点
Object = {}
Object.id = 1

function Object:Test()
    print("Test" .. self.id)
end

-- : 会自动将 调用这个函数的对象 作为第一个参数传入
function Object:new()
    -- self 默认传入的第一个参数
    -- 对象就是变量 返回一个新的变量
    -- 返回的内容 本质上就是表对象
    local obj = {}
    -- 元表知识 __index 当找自己的变量找不到时 去找元表当中__index指向的内容
    self.__index = self
    setmetatable(obj, self)

    return obj
end

local myObj = Object:new()
print(myObj)
print(myObj.id)             -- 1
myObj:Test()                -- Test1

myObj.id = 2
print(myObj.id)             -- 2
print(Object.id)            -- 1
myObj:Test()                -- Test2

print("****************继承****************")
-- 写一个用于继承的函数
function Object:subClass(className)
    -- _G表知识点 总表 所有声明的全局变量 都以键值对的形式存在其中
    _G[className] = {}
    -- 写相关继承的规则
    -- 用到元表
    local obj = _G[className]
    self.__index = self
    -- 子类 定义一个base属性 代表父类
    obj.base = self
    setmetatable(obj, self)
end

Object:subClass("Person")
print(Person)
print(Person.id)

local p1 = Person:new()
p1.id = 100
print(p1.id)
p1:Test()

Object:subClass("Monster")
local m1 = Monster:new()
m1. id = 200
print(m1.id)
m1:Test()

print("****************多态****************")
-- 相同行为 不用表象 就是多态
-- 相同方法 不同执行逻辑 就是多态
Object:subClass("GameObject")
GameObject.posX = 0
GameObject.posY = 0
function GameObject:Move()
    self.posX = self.posX + 1
    self.posY = self.posY + 1
    print(self.posX)
    print(self.posY)
end

GameObject:subClass("Player")
function Player:Move()
    -- base 指的是 GameObject 表(类)
    -- 这种方式调用 相当于把基类表 作为第一个参数传入方法中
    -- 避免把基类表 传入到方法中 否则就公用一张表的属性
    -- self.base:Move()     -- 不可取
    -- 如果要执行父类逻辑 不要使用冒号调用
    -- 通过.调用 然后自己传入参数
    self.base.Move(self)
end

local p1 = Player:new()
p1:Move()
p1:Move()
local p2 = Player:new()
p2:Move()
p1:Move()
p2:Move()